﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Personal_Cloud_Disk_PC_Client;

namespace Personal_Cloud_Disk_PC_Client
{
    public class EventMonitor
    {
        private Queue<CloudEvent> eventQueue = new Queue<CloudEvent>();
        private TaskScheduler taskScheduler;
        volatile bool monitorOn;
        private Thread monitorThread;

        public EventMonitor(TaskScheduler taskScheduler)
        {
            this.taskScheduler = taskScheduler;
            monitorThread = new Thread(new ThreadStart(this.handleEvent));
        }

        public void start()
        {
            monitorOn = true;
            Logger.write("Monitor starting, current state: " + monitorThread.ThreadState);
            if (monitorThread.ThreadState == ThreadState.Stopped || monitorThread.ThreadState == ThreadState.Unstarted) {
                monitorThread.Start();
            }
        }
        public void raiseEvent(CloudEvent theEvent)
        {
            Logger.write("Event raising: " + theEvent.ToString());
            if (monitorOn) {
                lock (eventQueue) {
                    eventQueue.Enqueue(theEvent);
                    Logger.write("Event Monitored: " + theEvent.ToString());
                }
            } else {
                Logger.write("Event Abandoned: " + theEvent.ToString());
            }
        }
        public void handleEvent()
        {
            Logger.write("handleEvent thread started!");
            while (monitorOn) {
                lock (eventQueue) {
                    if (eventQueue.Count == 0) {
                        Thread.Sleep(100);
                        continue;
                    }
                    CloudEvent theEvent = eventQueue.Dequeue();
                    CloudTask cloudTask = theEvent.handle();
                    taskScheduler.add(cloudTask);
                    Logger.write("Event Handled: " + theEvent.ToString());
                }
                Thread.Sleep(100);
            }
            this.saveEventQueue();
            Logger.write("handleEvent thread ended!");
        }

        private void saveEventQueue()
        {
            while (eventQueue.Count > 0) {
                CloudEvent theEvent = eventQueue.Dequeue();
                Logger.write("Event Save: " + theEvent.ToString());
            }
        }
        public void stop()
        {
            monitorOn = false;
        }
    }

    public class CloudEvent
    {
        public enum Side { Client, Server };
        public enum Entity { Directory, File };
        public enum Action { Create, Change, Delete };

        private Side side;
        private Entity entity;
        private Action action;
        private string uniqueName;

        public CloudEvent(Side side, Entity entity, Action action, string uniqueName)
        {
            this.side = side;
            this.entity = entity;
            this.action = action;
            this.uniqueName = uniqueName;
        }

        public CloudTask handle()
        {
            switch (this.side) {
                case Side.Client: {
                        switch (this.entity) {
                            case Entity.File: {
                                    switch (this.action) {
                                        case Action.Create: {
                                                return new UploadTask(this.uniqueName);
                                            }
                                        case Action.Change: {
                                                return new UploadTask(this.uniqueName);
                                            }
                                        case Action.Delete: {
                                                return new DeleteTask(this.uniqueName);
                                            }
                                    }
                                    break;
                                }
                            case Entity.Directory: {
                                    switch (this.action) {
                                        case Action.Create: {
                                                throw new NotImplementedException();
                                            }
                                        case Action.Change: {
                                                throw new NotImplementedException();
                                            }
                                        case Action.Delete: {
                                                throw new NotImplementedException();
                                            }
                                    }
                                    break;
                                }
                        }
                        break;
                    }
                case Side.Server: {
                    switch (this.entity) {
                        case Entity.File: {
                                    switch (this.action) {
                                        case Action.Create: {
                                                return new DownloadTask(this.uniqueName);
                                            }
                                        case Action.Change: {
                                                return new DownloadTask(this.uniqueName);
                                            }
                                        case Action.Delete: {
                                                throw new NotImplementedException();
                                            }
                                    }
                                    break;
                                }
                            case Entity.Directory: {
                                    switch (this.action) {
                                        case Action.Create: {
                                                throw new NotImplementedException();
                                            }
                                        case Action.Change: {
                                                throw new NotImplementedException();
                                            }
                                        case Action.Delete: {
                                                throw new NotImplementedException();
                                            }
                                    }
                                    break;
                                }
                        }
                        break;
                    }
                default: {
                        throw new NotImplementedException();
                    }

            }
            return null;
        }
    }
}
